<script lang="ts">
	import { setContext, onMount, onDestroy, untrack } from 'svelte';
	import { TableState } from './store/table-state.svelte';
	import { tableContextKey, type ColumnConfig } from './context/table-context';
	import { throttle } from 'lodash-es';
	import TableHeader from './components/TableHeader.svelte';
	import TableBody from './components/TableBody.svelte';
	import TableFooter from './components/TableFooter.svelte';
	import TableSettings from './components/TableSettings.svelte';
	import RectButton from '$lib/components/Basic/Button/RectButton.svelte';
	import Popover from '$lib/components/Basic/Popover/Popover.svelte';

	interface TableProps<T = Record<string, any>> {
		data: T[];
		// 是否开启虚拟滚动
		virtualized?: boolean;
		rowHeight?: number; //虚拟滚动单行行高
		// 是否开启多选
		multiple?: boolean;
		// 是否展示汇总行
		showSummary?: boolean;
		// 表格尺寸
		size?: 'sm' | 'md' | 'lg';
		// 是否展示边框
		border?: boolean;
		theadClass?: string;
		stripe?: boolean;
		summaryMethod?: (params: { columns: ColumnConfig[]; data: T[] }) => Record<string, any>;
		children?: any;
		// 新增：是否显示工具栏
		showToolbar?: boolean;
		// 新增：导出文件名
		exportFileName?: string;
	}

	let {
		data = [],
		virtualized = false,
		rowHeight,
		multiple = false,
		showSummary = false,
		size = 'md',
		border = false,
		theadClass = '',
		stripe = false,
		summaryMethod,
		children,
		showToolbar = false,
		exportFileName = 'table-data'
	}: TableProps = $props();
	// 初始化状态管理类
	let tableContainerRef: HTMLElement | undefined = $state(undefined);
	const rowHeightMap = { sm: 30, md: 34, lg: 40 };
	const actRowHeight = $derived(rowHeight ? rowHeight : rowHeightMap[size]);

	// 1. 初始化状态管理类
	const tableState = new TableState({ data, summaryMethod });
	const gridTemplateColumns = $derived(
		(multiple ? '30px ' : '') +
			tableState.columns
				.map((col, index) => {
					let width = tableState.columnWidths[col.key as string] || 'auto';
					if (index === tableState.columns.length - 1) {
						if (width !== 'auto') {
							return `calc(${width}px - ${tableState.bodyScrollbarWidth}px)`;
						}
					}

					return `${width}px`;
				})
				.join(' ')
	);

	// 2. 响应 data 变化
	$effect(() => {
		data;
		showSummary;
		untrack(() => {
			tableState.setData(data);
			tableState.triggerProcessData(data);
			tableState.showSummary = showSummary;
		});
	});
	// 3. 提供 Context
	setContext(tableContextKey, {
		addColumn: (config: ColumnConfig) => tableState.addColumn(config),
		removeColumn: (key: ColumnConfig['key']) => tableState.removeColumn(key)
	});

	// 4. 滚动同步逻辑 (保持在主组件，因为涉及 Header/Body/Footer 交互)
	let headerScrollContainerRef: HTMLElement | undefined = $state(undefined);
	let footerScrollContainerRef: HTMLElement | undefined = $state(undefined);

	const handleBodyScroll = ({ scrollLeft }: { scrollLeft: number }) => {
		if (headerScrollContainerRef) headerScrollContainerRef.scrollLeft = scrollLeft;
		if (footerScrollContainerRef) footerScrollContainerRef.scrollLeft = scrollLeft;
	};

	// 5. DPR 监听 & ResizeObserver (保持在主组件)
	let dpr = $state(1); // 默认为 1，防止 SSR 报错
	let dprMediaQuery: MediaQueryList | null = null;

	const updateDpr = () => {
		const newDpr = window.devicePixelRatio;

		// 只有真正变化时才更新
		if (newDpr !== dpr) {
			dpr = newDpr;
		}

		// 递归绑定：因为 resolution 值变了，旧的 listener 不会再触发，需要重新绑定
		bindDprListener();
	};

	const bindDprListener = () => {
		// 清理旧监听
		if (dprMediaQuery) {
			dprMediaQuery.removeEventListener('change', updateDpr);
		}
		// 创建新监听 (监听当前的精度)
		dprMediaQuery = window.matchMedia(`(resolution: ${window.devicePixelRatio}dppx)`);
		dprMediaQuery.addEventListener('change', updateDpr);
	};
	// 优化的列宽计算函数
	// 记忆化列宽计算结果
	let lastColumnsState = '';
	let columnTotalWidths: number = $state(0);
	let tableContainerWidth: number = $state(0);
	let totalWidth: number = $state(0);
	const handleResize = throttle(() => {
		if (!tableContainerRef) return;

		const containerWidth =
			tableContainerRef.offsetWidth - (multiple ? 30 : 0) - (border ? 2 : 0) - 1;
		if (containerWidth === tableContainerWidth) return;
		tableContainerWidth = containerWidth;

		// 性能优化：使用更高效的缓存策略
		const currentColumnsState = tableState.columns
			.map((col) => col.key + ':' + col.width + ':' + col.minWidth)
			.join('|');
		if (currentColumnsState === lastColumnsState && containerWidth === totalWidth) {
			return;
		}
		columnTotalWidths = 0;

		// 更新缓存状态
		lastColumnsState = currentColumnsState;
		totalWidth = containerWidth;

		// 使用Map预分配，减少对象属性访问次数
		const newColumnWidths = new Map<string, number>();

		// 区分固定列（有width）和弹性列（无width但有minWidth）
		const fixedColumns = tableState.columns.filter((col) => col.width > 0);
		const flexWithMinColumns = tableState.columns.filter(
			(col) => col.width <= 0 && col.minWidth > 0
		);
		const noConfigColumns = tableState.columns.filter((col) => col.width <= 0 && col.minWidth <= 0);

		// 计算固定列总宽度
		const fixedTotal = fixedColumns.reduce((sum, col) => sum + col.width, 0);
		// 计算弹性列的总最小宽度
		const flexMinTotal = flexWithMinColumns.reduce((sum, col) => sum + col.minWidth, 0);
		const requiredTotal = fixedTotal + flexMinTotal;

		// 剩余可分配空间 = 容器总宽 - 固定列总宽
		const remainingSpace = Math.max(0, totalWidth - requiredTotal);

		// 1. 处理固定列：直接使用设定的width
		for (const col of fixedColumns) {
			newColumnWidths.set(col.key as string, col.width);
		}
		// 2. 处理弹性列：按minWidth比例分配剩余空间
		if (flexWithMinColumns.length > 0) {
			if (remainingSpace <= 0 || noConfigColumns.length > 0) {
				// 空间不足：仅保留minWidth
				for (const col of flexWithMinColumns) {
					newColumnWidths.set(col.key as string, col.minWidth);
				}
			} else {
				// 空间充足：多余空间按minWidth比例分配
				const extraSpace = remainingSpace;
				// 只计算一次总和
				const totalFlexMin = flexMinTotal; // 复用上面计算的结果
				for (const col of flexWithMinColumns) {
					const proportion = col.minWidth / totalFlexMin;
					const finalWidth = Math.floor(col.minWidth + extraSpace * proportion);
					newColumnWidths.set(col.key as string, finalWidth);
				}
			}
		}

		// 3. 处理无配置列：均分剩余空间（无其他列时占满容器）
		if (noConfigColumns.length > 0) {
			// 无配置列最小宽度默认50px（避免过窄）
			const minNoConfigWidth = 70;
			const totalNoConfigMin = noConfigColumns.length * minNoConfigWidth;

			if (remainingSpace <= totalNoConfigMin) {
				// 剩余空间不足：每列按最小宽度分配
				for (const col of noConfigColumns) {
					newColumnWidths.set(col.key as string, minNoConfigWidth);
				}
			} else {
				// 剩余空间充足：均分剩余空间
				const perNoConfigWidth = Math.floor(remainingSpace / noConfigColumns.length);
				for (const col of noConfigColumns) {
					newColumnWidths.set(col.key as string, perNoConfigWidth);
				}
			}
		}

		// 批量更新columnWidths，减少响应式更新次数
		// 创建新对象而不是直接修改，确保响应式更新正确触发
		const updatedWidths: Record<string, number> = {};
		newColumnWidths.forEach((value, key) => {
			updatedWidths[key] = value;
			columnTotalWidths += value;
		});
		tableState.columnWidths = updatedWidths;
	}, 30); // 增加节流时间，减少高频调整时的计算
	let observer: ResizeObserver;
	onMount(() => {
		if (!tableContainerRef) return;
		observer = new ResizeObserver(handleResize);
		observer.observe(tableContainerRef);
		// 🔥 初始化 DPR
		if (typeof window !== 'undefined') {
			dpr = window.devicePixelRatio;
			bindDprListener();
		}
	});

	onDestroy(() => {
		if (tableContainerRef && observer) {
			observer.unobserve(tableContainerRef);
		}
		// 🔥 清理 DPR 监听
		if (dprMediaQuery) {
			dprMediaQuery.removeEventListener('change', updateDpr);
		}
	});
	const exportExcel = () => {
		tableState.exportToExcel(exportFileName);
	};
</script>

<!-- 渲染隐藏的 Column 组件以注册配置 -->
{@render children?.()}

<div
	class="table-container"
	class:virtualized
	class:summary={showSummary}
	class:is-horizontal={tableState.bodyScrollbarWidth > 0}
	bind:this={tableContainerRef}
	style:--grid-cols={gridTemplateColumns}
	style:--row-height={`${actRowHeight}px`}
	style:--checkbox-color="var(--color-primary-600)"
	style:--dpr={dpr}
>
	{#if showToolbar}
		<div class="table-toolbar">
			<div class="toolbar-left">
				<!-- 这里可以预留插槽给用户放自己的按钮 -->
			</div>
			<div class="toolbar-right">
				<RectButton
					{size}
					icon="file/export-excel"
					onClick={exportExcel}
					style="margin-right: 8px;"
					type="filled"
					variant="primary"
				>导出</RectButton>

				<Popover placement="bottom-end" offset={6}>
					{#snippet triggerSnippet()}
						<RectButton {size} icon="office/table-setting" type="ghost" variant="primary">配置</RectButton>
					{/snippet}
					{#snippet contentSnippet()}
						<TableSettings {tableState} {size}/>
					{/snippet}
				</Popover>
			</div>
		</div>
	{/if}
	<div
		class="table-content"
		class:table--border={border}
		class:small={size === 'sm'}
		class:medium={size === 'md'}
		class:large={size === 'lg'}
	>
		<TableHeader
			{tableState}
			bind:headerScrollContainerRef
			bind:tableContainerRef
			{actRowHeight}
			{multiple}
			{size}
			{theadClass}
			{border}
		/>
		<TableBody
			{tableState}
			{actRowHeight}
			{virtualized}
			{size}
			{multiple}
			{border}
			{stripe}
			onScroll={handleBodyScroll}
		/>
		{#if showSummary}
			<TableFooter {tableState} {actRowHeight} {multiple} {border} bind:footerScrollContainerRef />
		{/if}
	</div>
</div>

<style lang="scss">
	@use './styles/table.scss';
</style>
